package com.smedi.ismedi.organization.core.domain.service.impl;

import com.smedi.ismedi.organization.core.domain.aggregatemodel.HrOrganization;
import com.smedi.ismedi.organization.core.domain.repository.HrOrganizationRepository;
import com.smedi.ismedi.organization.core.domain.service.HrOrganizationDomainService;
import com.smedi.ismedi.organization.core.infrastructure.constant.ConstantField;
import com.smedi.ismedi.organization.core.infrastructure.constant.CustomError;
import com.smedi.ismedi.organization.core.infrastructure.enumerate.HrOrganizationTypeEnum;
import com.smedi.ismedi.organization.core.port.adapter.service.ConstructionProjectRemoteApiService;
import com.smedi.ismedi.organization.core.port.adapter.service.PersonnelRemoteApiService;
import com.smedi.ismedi.web.starter.exception.LogicException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;

@Slf4j
@Service
@AllArgsConstructor
public class HrOrganizationDomainServiceImpl implements HrOrganizationDomainService {
    private final HrOrganizationRepository hrOrganizationRepository;

    private final PersonnelRemoteApiService personnelRemoteApiService;

    private final ConstructionProjectRemoteApiService constructionProjectRemoteApiService;

    /**
     * 生成默认的组织排序
     *
     * @param parentId
     * @return
     */
    private Integer generateDisplayOrder(Long parentId) {
        List<HrOrganization> hrOrganizations = hrOrganizationRepository.selectByParentId(parentId);
        Optional<HrOrganization> max = hrOrganizations.stream().max(Comparator.comparingLong(hrOrganization ->
                hrOrganization.getDisplayOrder() != null ? hrOrganization.getDisplayOrder() : 0L
        ));
        if (max.isPresent()) {
            return max.get().getDisplayOrder() != null ? (max.get().getDisplayOrder() + 1) : 0;
        } else {
            return 0;
        }
    }

    /**
     * 获取当前组织属于第几层级
     *
     * @param parentId
     * @return
     */
    private int getCurrentHrOrganizationLevel(Long parentId) {
        int level = 0;
        HrOrganization hrOrganization = hrOrganizationRepository.selectByHrOrganizationId(parentId);
        if (hrOrganization != null) {
            if (hrOrganization.getParentId() != null && !hrOrganization.isRoot()) {
                level += this.getCurrentHrOrganizationLevel(hrOrganization.getParentId()) + 1;
            } else {
                level += 1;
            }
        } else {
            level += 1;
        }
        return level;
    }

    /**
     * 判断父级组织类型是否符合业务
     *
     * @param parent
     * @param current
     */
    private void validateParentHrOrganization(HrOrganization parent, HrOrganization current) {
        if (HrOrganizationTypeEnum.COMPANY_LEADER.getValue().equals(parent.getType())) {
            // 公司领导下级不可新建组织
            throw LogicException.raise(CustomError.HR_ORG_CREATE_ERROR1);
        } else if (HrOrganizationTypeEnum.COMPANY_MANAGEMENT_ORGANIZATION.getValue().equals(parent.getType())) {
            // 公司管理组织下级可新建下级部门
            if (!HrOrganizationTypeEnum.SUBORDINATE_ORGANIZATION.getValue().equals(current.getType())) {
                throw LogicException.raise(CustomError.HR_ORG_CREATE_ERROR2);
            }
        } else if (HrOrganizationTypeEnum.PROJECT_MANAGEMENT_ORGANIZATION.getValue().equals(parent.getType())) {
            // 项目管理组织下级可新建下级部门
            if (!HrOrganizationTypeEnum.SUBORDINATE_ORGANIZATION.getValue().equals(current.getType())) {
                throw LogicException.raise(CustomError.HR_ORG_CREATE_ERROR3);
            }
        } else if (HrOrganizationTypeEnum.SUBORDINATE_ORGANIZATION.getValue().equals(parent.getType())) {
            // 下级部门下级可新建下级部门
            if (!HrOrganizationTypeEnum.SUBORDINATE_ORGANIZATION.getValue().equals(current.getType())) {
                throw LogicException.raise(CustomError.HR_ORG_CREATE_ERROR4);
            }
        }
        // 判断当前父节点组织是否是当前组织的下属组织
        if (current != null) {
            List<HrOrganization> list = this.getHrOrganizationChildrenByList(current.getHrOrganizationId()); // 获取当前组织下的所有子节点，主要应对更新，一般新增不会有这块问题
            Optional<HrOrganization> optional = list.stream().filter(i -> i.getHrOrganizationId().equals(parent.getHrOrganizationId())).findFirst();
            if (optional.isPresent()) {
                throw LogicException.raise(CustomError.PARENT_ORG_CANNOT_BE_SON_NODE);
            }
        }
    }

    @Override
    public HrOrganization save(HrOrganization data) {
        HrOrganization basic;
        if (data.getHrOrganizationId() != null) {
            basic = hrOrganizationRepository.selectByHrOrganizationId(data.getHrOrganizationId());
            if (basic == null) {
                throw LogicException.raise(CustomError.HR_ORGANIZATION_NOT_EXIST);
            } else {
                basic.setDisplayOrder(data.getDisplayOrder());
            }
        } else {
            basic = new HrOrganization()
                    .setDisplayOrder(generateDisplayOrder(data.getParentId()));
        }

        basic.setOrganizationCode(data.getOrganizationCode())
                .setFullName(data.getFullName())
                .setShortName(data.getShortName())
                .setType(data.getType());

        // 判断组织全称是否重复
        if (duplicateFullName(basic.getFullName(), basic.getHrOrganizationId())) {
            throw LogicException.raise(CustomError.ORG_FULL_NAME_DUPLICATE);
        }
        // 判断组织简称是否重复
        if (duplicateShortName(basic.getShortName(), basic.getHrOrganizationId())) {
            throw LogicException.raise(CustomError.ORG_SHORT_NAME_DUPLICATE);
        }
        // 判断组织编码是否重复
        if (duplicateCode(basic.getOrganizationCode(), basic.getHrOrganizationId())) {
            throw LogicException.raise(CustomError.ORG_CODE_DUPLICATE);
        }

        // 组织层级限制10层
        if (this.getCurrentHrOrganizationLevel(data.getParentId()) > ConstantField.maxOrganizationLevel) {
            throw LogicException.raise(CustomError.ORG_MAX_LEVEL_ERROR);
        }

        // 只有项目管理组织下才可以新建项目
        if (basic.getHrOrganizationId() != null && !HrOrganizationTypeEnum.PROJECT_MANAGEMENT_ORGANIZATION.getValue().equals(basic.getType())) {
            if (constructionProjectRemoteApiService.checkHrOrganizationHasProject(basic.getHrOrganizationId())) {
                throw LogicException.raise(CustomError.ONLY_PROJECT_MANAGE_ORG_WITH_PROJECT);
            }
        }

        // 判断父节点组织是否存在，如果不存在则显示报错
        if (data.getParentId() != null) {
            if (data.getHrOrganizationId() != null) {
                if (data.getHrOrganizationId().equals(data.getParentId())) {
                    throw LogicException.raise(CustomError.PARENT_ORG_MYSELF_WRONG);
                }
            }
            HrOrganization parent = hrOrganizationRepository.selectByHrOrganizationId(data.getParentId());
            if (parent == null) {
                throw LogicException.raise(CustomError.PARENT_ORG_NOT_EXIST);
            } else {
                // 判断父级组织是否可以创建
                validateParentHrOrganization(parent, data);
            }

            basic.setParentId(data.getParentId())
                    .setRoot(false);
        } else {
            // 判断当前租户下是否已经存在根节点组织
            HrOrganization root = hrOrganizationRepository.selectHrOrganizationRoot();
            if (root != null) {
                if (!root.getHrOrganizationId().equals(basic.getHrOrganizationId())) {
                    throw LogicException.raise(CustomError.EXIST_ORG_ROOT);
                }
            }
            // 判断当前组织是否为公司
            if (HrOrganizationTypeEnum.COMPANY.getValue().equals(basic.getType())) {
                basic.setRoot(true); // 根
            } else {
                throw LogicException.raise(CustomError.ONLY_COMPANY_CAN_BE_ROOT);
            }
        }

        // 保存数据
        HrOrganization domain = (data.getHrOrganizationId() == null) ? hrOrganizationRepository.doInsert(basic) : hrOrganizationRepository.doUpdate(basic);
        // 赋值数据
        domain.setTypeMeaning(HrOrganizationTypeEnum.getName(domain.getType()));
        return domain;
    }

    @Override
    public void delete(Long hrOrganizationId) {
        HrOrganization basic = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
        if (basic == null) {
            throw LogicException.raise(CustomError.HR_ORGANIZATION_NOT_EXIST);
        }

        // 判断组织下是否有人
        if (personnelRemoteApiService.checkHrOrganizationHasPerson(hrOrganizationId)) {
            throw LogicException.raise(CustomError.ORG_HAS_ASSIGNMENT);
        }

        // 判断组织下是否挂了子组织
        List<HrOrganization> list = this.getHrOrganizationChildrenByList(hrOrganizationId);
        if (list.size() > 0) {
            throw LogicException.raise(CustomError.ORG_DELETE_FAILED_BY_HAS_CHILDREN);
        }

        // 判断组织下是否有项目
        if (constructionProjectRemoteApiService.checkHrOrganizationHasProject(hrOrganizationId)) {
            throw LogicException.raise(CustomError.HR_ORG_HAS_PROJECT);
        }

        // 执行删除
        hrOrganizationRepository.doDelete(basic);
    }

    @Override
    public List<HrOrganization> getHrOrganizationChildrenByList(Long hrOrganizationId) {
        Set<HrOrganization> set = new HashSet<>();
        HrOrganization basic = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
        if (basic != null) {
            // 组织类型
            basic.setTypeMeaning(HrOrganizationTypeEnum.getName(basic.getType()));
            // 获取当前节点下的组织信息
            List<HrOrganization> nodes = hrOrganizationRepository.selectByParentId(basic.getHrOrganizationId());
            for (HrOrganization i : nodes) {
                i.setTypeMeaning(HrOrganizationTypeEnum.getName(i.getType())) // 组织类型
                        .setParentFullName(basic.getFullName())  // 上级组织名称
                        .setParentShortName(basic.getShortName());  // 上级组织名称
                set.add(i); // 添加自身组织
                if (i.getHrOrganizationId() != null) {
                    set.addAll(getHrOrganizationChildrenByList(i.getHrOrganizationId()));
                }
            }
        }
        return new ArrayList<>(set);
    }

    @Override
    public List<HrOrganization> getHrOrganizationChildrenByTree(Long hrOrganizationId) {
        List<HrOrganization> list = new ArrayList<>();
        HrOrganization basic = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
        if (basic != null) {
            // 获取当前节点下的组织信息
            List<HrOrganization> nodes = hrOrganizationRepository.selectByParentId(basic.getHrOrganizationId());
            for (HrOrganization i : nodes) {
                i.setTypeMeaning(HrOrganizationTypeEnum.getName(i.getType())) // 组织类型
                        .setParentFullName(basic.getFullName())  // 上级组织全称
                        .setParentShortName(basic.getShortName());  // 上级组织简称
                // 添加子组织
                if (i.getHrOrganizationId() != null) {
                    i.setHrOrganizationChildren(getHrOrganizationChildrenByTree(i.getHrOrganizationId()));
                }
                list.add(i); // 添加自身组织
            }
        }
        return list;
    }

    @Override
    public List<HrOrganization> getHrOrganizationChildrenByTreeWithTypeList(Long hrOrganizationId, List<String> typeList) {
        List<HrOrganization> list = new ArrayList<>();
        HrOrganization basic = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
        if (basic != null) {
            // 获取当前节点下的组织信息
            List<HrOrganization> nodes = hrOrganizationRepository.selectByParentId(basic.getHrOrganizationId());
            for (HrOrganization i : nodes) {
                i.setTypeMeaning(HrOrganizationTypeEnum.getName(i.getType())) // 组织类型
                        .setParentFullName(basic.getFullName())  // 上级组织全称
                        .setParentShortName(basic.getShortName());  // 上级组织简称
                // 添加子组织
                if (i.getHrOrganizationId() != null) {
                    i.setHrOrganizationChildren(getHrOrganizationChildrenByTreeWithTypeList(i.getHrOrganizationId(), typeList));
                }
                // 节点i的类型属于特定类型，则加入节点列表
                if (typeList.contains(i.getType())) {
                    list.add(i); // 添加自身组织
                }
            }
        }
        return list;
    }

    @Override
    public Boolean validateHrOrganization(Long hrOrganizationId) {
        HrOrganization hrOrganization = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
        return (hrOrganization != null);
    }

    @Override
    public long updateHrOrgByShortName(String shortName, String dingDeptKey) {
        return hrOrganizationRepository.updateHrOrgByShortName(shortName,dingDeptKey);
    }

    @Override
    public Boolean duplicateFullName(String fullName, Long hrOrganizationId) {
        return hrOrganizationRepository.selectFullNameCount(fullName, hrOrganizationId) > 0;
    }

    @Override
    public Boolean duplicateShortName(String shortName, Long hrOrganizationId) {
        return hrOrganizationRepository.selectShortNameCount(shortName, hrOrganizationId) > 0;
    }

    @Override
    public Boolean duplicateCode(String code, Long hrOrganizationId) {
        return hrOrganizationRepository.selectOrganizationCodeCount(code, hrOrganizationId) > 0;
    }

    @Override
    public Boolean validateHrOrganizationCanHasProject(Long hrOrganizationId) {
        HrOrganization hrOrganization = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
        if (hrOrganization != null) {
            // 判断当前组织的类型是否是项目管理组织
            return (HrOrganizationTypeEnum.PROJECT_MANAGEMENT_ORGANIZATION.getValue().equals(hrOrganization.getType()));
        } else {
            return false;
        }
    }

    @Override
    public void saveHrOrganizationDisplayOrder(Long hrOrganizationId, Integer displayOrder) {
        HrOrganization basic = hrOrganizationRepository.selectByHrOrganizationId(hrOrganizationId);
        if (basic == null) {
            throw LogicException.raise(CustomError.HR_ORGANIZATION_NOT_EXIST);
        }

        if (displayOrder == null) {
            throw LogicException.raise(CustomError.DISPLAY_ORDER_MISS);
        }
        basic.setDisplayOrder(displayOrder);
        hrOrganizationRepository.doUpdate(basic);
    }
}
